# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import numpy as np
import matplotlib.pyplot as plt
from mnist import load_mnist
from two_layer_net import TwoLayerNet

# 读入数据
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
# 这里的结构是784*50*50*10

iters_num = 10000  # 适当设定循环的次数
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1

train_loss_list = []
train_acc_list = []
test_acc_list = []

iter_per_epoch = max(train_size / batch_size, 1)
#每个epoch我要迭代多少批的数据
# 每次只处理一batch的数据

for i in range(iters_num):
    # iters_num这个参数其实没有太大的用处,因为我们最终需要的是根据epoch的增加,模型精度的变化曲线,所以这里的iters_num只是起到了一个停止训练的作用
    batch_mask = np.random.choice(train_size, batch_size)#意思就是train_size个数据中随机选择batch_size条数据,返回的是下标
    x_batch = x_train[batch_mask]#根据下标获取裸数据
    t_batch = t_train[batch_mask]#根据下标获取类别标签
    
    # 计算梯度
    #grad = network.numerical_gradient(x_batch, t_batch)
    grad = network.gradient(x_batch, t_batch)



    # 更新参数
    for key in ('W1', 'b1', 'W2', 'b2'):
        network.params[key] -= learning_rate * grad[key]
        #使用梯度来对整个网络的权重做更新,每个batch都要更新一次权重
        # wji=wji−ε△w
    loss = network.loss(x_batch, t_batch)#计算损失函数
    train_loss_list.append(loss)
    
    if i % iter_per_epoch == 0:
        #判断当前处理的数据的量是否等于整个数据集的量(也就是一次epoch),
        # 如果等于的话,那么记录各种参数
        train_acc = network.accuracy(x_train, t_train)
        test_acc = network.accuracy(x_test, t_test)
        train_acc_list.append(train_acc)
        test_acc_list.append(test_acc)
        print("train acc, test acc | " + str(train_acc) + ", " + str(test_acc))

# 绘制图形
markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, label='train acc')
plt.plot(x, test_acc_list, label='test acc', linestyle='--')
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()